# write by hasaki
# 功能：先获取从coding clone的引擎源码目录，然后在同一目录下复制一份，在把里面的py文件进行加密处理
# 一，先clone源码
# 二，遍历源码，若有.py文件，则进行加密
# 三，加密后的pyd文件复制进源码，删除源码的源文件
# 四，把加密后的目录打包发送到引擎版本文件服务器
# pyd不能直接用python去执行，要Import去执行
# 报错ImportError: DLL load failed: %1 不是有效的 Win32 应用程序
import os
import sys

import subprocess
import platform
import shutil
import json
import codecs

import requests


class MakePydAndSo:
    def __init__(self):
        '''把python代码加密'''
        # {'目录':[{'子目录':[],'文件名':'后缀','文件名':'.py'}]}
        self.os_path=os.getcwd()                         # python 启动的文件位置
        self.python_code_file=''                         # 源代码文件地址
        self.current_path=os.getcwd()                    # 遍历到的当前目录
        self.json_data={'engineVersion':'develop'}       # 命令行输入的 参数
        self.current_platform=platform.platform()        # 当前系统类型
        self.pyd_file_path=''                            # 生成pyd的路径
        self.pyd_file=''                                 # pyd文件

        self.current_file_name=''                        # 当前遍历到文件的名称
        self.is_py_file=False                            # 判断当前文件是否是python文件

    def judge_platform(self):
        '''判断当前的系统是什么'''
        if 'Window' in self.current_platform[:7]:
            print('当前系统是window ')
        elif 'Linux' in self.current_platform[:7]:
            print('当前系统是linux')
        else:
            raise Exception('出现不是预设的系统:',self.current_platform)
    
    def clone_engine_file(self):
        '''从git下载引擎文件'''
        print('start to clone the origin code')
        down_engine_path=''
        git_address=''
        git_order='git clone --branch {} https://kashaki:aa231495877@{}'.format(self.json_data['engineVersion'],git_address)
        git=subprocess.call(git_order,shell=True)
        print('finish to clone the origin code')
    
    def check_py(self):
        '''判断是不是python文件，如果是就返回名称'''
        if self.current_file_name[-3:]=='.py':
            print('找到一个python文件',self.current_file_name)
            self.is_py_file=True
        else:
            print('这不是python文件，该文件是：',self.current_file_name)
            self.is_py_file=False
        
    def setup_function(self):
        ''' 把file_name 进行pyd化
            win平台下pyd文件生成在setup.py文件的相同目录下，同时生成build文件夹和Lib文件夹
            linux平台下so文件生成在setup.py文件的相同目录下，so文件就在这个目录下
        '''
        if self.is_py_file:
            if 'Linux' in self.current_platform[:7]:
                print('把{} 进行pyd化'.format(self.current_file_name))
                subprocess_order='python setup.py {} build_ext --inpace'.format(self.current_path+'/'+self.current_file_name)
                subprocess.call(subprocess_order,shell=True)
                print('pyd 生成成功：',self.current_file_name)

            elif 'Window' in self.current_platform[:7]:
                print('把{} 进行pyd化'.format(self.current_file_name))
                temp=self.current_path+'/'+self.current_file_name
                json_data={'path':temp}
                # 写入json格式,加密的时候，通过文件名列表加密
                with open(self.os_path+'/hasaki.json','w',encoding='utf-8') as json_file:
                    json.dump(json_data,json_file,ensure_ascii=False)

                subprocess_order='python setup.py build_ext --inplace'
                subprocess.call(subprocess_order,shell=True)
                print('c文件 生成成功：',self.current_file_name)

                print('开始生成pyd')
                subprocess_order2='python setup.py install --prefix={}'.format(self.os_path)
                subprocess.call(subprocess_order2,shell=True)
                print('生成pyd成功',temp,'Lib地址：',self.os_path)
            else:
                raise Exception("unexpect system platform . Raise error by optimistic")


    def move_pyd(self):
        '''把pyd生成的lib/side-package下的pyd复制到源代码的原目录里'''
        print('把pyd文件复制到指定的目录path')
        # 截取python文件名不要后缀，为了删除同文件名的.c文件和.py文件
        current_pyd_file=self.find_pyd_full_name()
        # 如果那个文件目录没有python加密文件
        if current_pyd_file is None:
            return

        self.pyd_file=self.pyd_file_path+'/'+current_pyd_file

        if 'Linux' in self.current_platform[:7]:
            temp_before=self.current_path+'/'+self.current_file_name
            temp=temp_before.replace('.py','.so')                   # Linux平台的加密文件结尾是以.so结尾的
        
        elif 'Window' in self.current_platform[:7]:
            temp=self.current_path+'/'+self.current_file_name+'d'   # 原文件路径加文件名再加上d

        shutil.copyfile(self.pyd_file,temp)
        print('Move pyd file successed!!',temp)
    
    def delete_py_file(self):
        '''把pyd复制到源代码的原目录下后，删除源代码'''
        print('删除后缀为.py的file_name python文件')
        os.remove(self.current_path+'/'+self.current_file_name)
        print('delete origin code success',self.current_file_name)

    def delete_C_file(self):
        '''删除加密过程中产生的c文件'''
        if self.is_py_file:
            print('删除后缀为.C文件')
            c_file_name=self.current_file_name.replace('.py','.c')
            os.remove(self.current_path+'/'+c_file_name)
            print('删除后缀为.c文件成功')
    
    # ------------------------------------------------------------------------------------------
    # 辅助主流程的功能
    def find_pyd_full_name(self):
        '''找到加密文件的全名
            如：main.cp36-win_amd64.pyd
        '''
        for i,j,k in os.walk(self.pyd_file_path):
            for k_i in k:
                if k_i.split('.')[0]==self.current_file_name.replace('.py',''):
                    return k_i

    # ------------------------------------------------------------------------------------------
    def setting(self,origin_code_path):
        '''一些启动设置'''
        self.judge_platform()
        #self.clone_engine_file()
        self.python_code_file=origin_code_path

        # 指定加密文件生成的位置
        if 'Linux' in self.current_platform:
            pass
        
        elif 'Window' in self.current_platform:
            self.pyd_file_path=self.os_path+'/Lib/site-packages/'
        
        else:
            raise Exception('什么乱七八槽的系统，没有识别到是win或者是linux系统')

    def run(self):
        '''开始遍历源代码'''
        for i,j,k in os.walk(self.python_code_file):
            # 只有目录没有文件得情况
            if k==[]:
                continue
            
            # 有目录也有文件的情况,先遍历该目录下所有的文件，k_i就是文件名称
            self.current_path=i
            for k_i in k:
                self.current_file_name=k_i
                self.check_py()
                self.setup_function()
                self.move_pyd()
                #self.delete_py_file()
                self.delete_C_file()

if __name__=='__main__':
    a=MakePydAndSo()
    python_code='C:/hashaki/工作交接'     # 需要加密的python 源代码文件夹
    a.setting(python_code)
    a.run()